package org.vacoor.xqq.core.mod.receviver.impl;

import com.fasterxml.jackson.databind.node.ObjectNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vacoor.nothing.common.json.Jacksons;
import org.vacoor.xqq.core.Constants;
import org.vacoor.xqq.core.EventBusHolder;
import org.vacoor.xqq.core.bean.ChatToken;
import org.vacoor.xqq.core.http.HttpRequestor;
import org.vacoor.xqq.core.http.Request;
import org.vacoor.xqq.core.http.RequestCallbackAdapter;
import org.vacoor.xqq.core.http.Response;
import org.vacoor.xqq.core.mod.authc.impl.WebQQAccessToken;
import org.vacoor.xqq.core.mod.client.impl.WebQQClient;
import org.vacoor.xqq.core.mod.receviver.MessageReceiver;
import org.vacoor.xqq.core.poll.PollReply;
import org.vacoor.xqq.core.poll.PollResult;

import javax.swing.*;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.List;
import java.util.concurrent.ExecutionException;

/**
 * 消息接收器
 * {"retcode":0,"result":[{"poll_type":"system_message","value":{"seq":52786,"type":"verify_required","uiuin":"","from_uin":4077369286,"account":2213328508,"onMsg":"","allow":1,"stat":20}}]}
 * <p/>
 * <p/>
 * User: vacoor
 */
public class SimpleMessageReceiver extends Thread implements MessageReceiver {
    public static final Logger logger = LoggerFactory.getLogger(SimpleMessageReceiver.class);

    private boolean keepPoll = false;
    private ChatToken token;
    private long minInterval = 2000;

    public SimpleMessageReceiver(ChatToken token) {
        super("MessageReceiver");
        this.token = token;
        this.setDaemon(true);
        EventBusHolder.getEventBus().register(this);
    }

    @Override
    public void run() {
        logger.info("启动消息接收...");
        keepPoll = true;
        while (keepPoll) {
            final long start = System.currentTimeMillis();
            logger.debug("keepPoll");
            WebQQAccessToken token = WebQQClient.getCurrentClient().getWebQQAccessToken();
            ObjectNode pollParam = createPollParamObject();
            try {
                HttpRequestor.getInstance().send(
                        new Request(Constants.U_POLL, Request.HttpMethod.POST)
                                .addHeader("Referer", Constants.H_REFERER)
                                .addHeader("Connection", "keep-alive")
                                .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                                .addParameter("r", pollParam),
                        new RequestCallbackAdapter() {
                            @Override
                            public void onSuccess(Response resp) throws IOException {
                                resolve(resp.getContent().asString());
                            }

                            @Override
                            public void onException(Exception ex) {
                                logger.warn("poll fail:", ex.getMessage());

                                try {
                                    Thread.sleep((ex instanceof SocketTimeoutException ? 3 : 3) * 1000);
                                } catch (InterruptedException ignore) {
                                }
                            }

                            @Override
                            public void onFailure(Response resp) {
                                logger.warn("poll failure: {}", resp);
                                try {
                                    Thread.sleep(15 * 1000);
                                } catch (InterruptedException ignore) {
                                }
                            }
                        }
                ).get();
                final long time = System.currentTimeMillis() - start;
                logger.debug("用时: {} s", time / 1000);
                if (time < minInterval) {
                    Thread.sleep(minInterval - time);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

    public void resolve(final String json) {
        logger.debug("resolve: {}", json);
        PollResult result = PollResult.formJson(json);
        switch (result.getStatusCode()) {
            case PollResult.SC_MESSAGE:
                List<PollReply> replies = result.getMessages();
                doPublishReply(replies.toArray(new PollReply[replies.size()]));
                break;
            case PollResult.SC_UPDATE_PTWEBQQ:
                doUpdatePtwebqq(result.getPtwebqq());
                break;
            case PollResult.SC_NORMAL:
                doNormal();
                break;
            case PollResult.SC_SELF_EXIT:
            case PollResult.SC_SELF_EXIT2:
                doSelfExit();
                break;
            case PollResult.SC_NOT_RELOGIN:
            case 103:       // TODO 103 确定103 和 100 区别, 103 没有登陆, 100 没有重新登陆, 也需要重新登陆
                doNotRelogin();
                break;
            case PollResult.SC_RELINK_FAIL:
            case PollResult.SC_RELINK_FAIL2:
                doRelinkFail();
                break;
            default:
                doUnknow(json);
        }
    }

    /**
     * 创建一个 poll 参数对象
     * {"clientid":57671299,"psessionid":"...","ptwebqq":"","key":""}
     */
    ObjectNode createPollParamObject() {
        WebQQAccessToken token = WebQQClient.getCurrentClient().getWebQQAccessToken();
        return Jacksons.createObjectNode()
                .put("clientid", token.getClientId())
                .put("psessionid", token.getPsessionId())
//                .put("ptwebqq", token.getPtwebqq())     // TODO 这个参数不要也可以吧
                .put("key", 0);
    }

    public void doPublishReply(PollReply... replies) {
        if (replies == null) {
            return;
        }

        for (PollReply pollReply : replies) {
            logger.debug("publish pollReply: {}", pollReply);
            EventBusHolder.getEventBus().post(pollReply);
        }
    }

    public void doUpdatePtwebqq(String newPtwebqq) {
        logger.debug("update ptwebqq: {}", newPtwebqq);
        // cookie 中ptwebqq 不能改
        WebQQClient.getCurrentClient().getWebQQAccessToken().setPtwebqq(newPtwebqq);
    }

    public void doSelfExit() {
        logger.info("客户端主动退出");
        shutdown();
    }

    public void doNormal() {
        logger.info("poll complete");
    }

    public void doUnknow(String content) {
        logger.warn("无法解析 Poll 响应: {}", content);
    }

    public void doNotRelogin() {
        for (int i = 0; i < 3; i++) {
            try {
//                        Thread.sleep(15 * 1000);
                logger.info("relink...");
                WebQQClient.getCurrentClient().relink();
                logger.info("relink success...");
                break;
            } catch (Throwable ae) {
                if (i == 2) {
                    shutdown();
                    JOptionPane.showMessageDialog(null, ae, "重新连接到服务器失败", JOptionPane.ERROR_MESSAGE);
                }
            }
        }
    }

    private void doRelinkFail() {
        logger.debug("重新连接失败, 必须重新登陆");
        shutdown();
    }

    @Override
    public void shutdown() {
        keepPoll = false;
        logger.info("receive stop");
    }
}
